package com.hzqy.service.wchat;

import com.alibaba.fastjson.JSONObject;
import com.hzqy.commons.utils.MD5Util;
import com.hzqy.commons.utils.SystemConfigUtils;
import com.hzqy.commons.utils.WChatPayUtil;
import com.hzqy.commons.utils.XMLUtil;
import com.hzqy.persistence.dao.wchat.WchatPayDao;
import com.hzqy.web.vo.*;
import com.swetake.util.Qrcode;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

@Service
public class WchatScanPayService {

	protected final Logger LOG = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private WchatPayDao wchatPayDao;


	public Map<String, Object> wchatpayCreateOrder(WchatPaymentVo payment) {
		Map<String, Object> resultMap = new HashMap<>();
		resultMap.put("success", false);
		SysProductVo product = getProduct(String.valueOf(payment.getProduct_id()));
		payment.setTrade_no(WChatPayUtil.createOrderId());
		payment.setProductcode(product.getF_sp_productcode());
		payment.setProductname(product.getF_sp_name());
		payment.setProductfee(product.getF_sp_fee());
		payment.setProducttype(product.getF_sp_type());

		Map<String, Object> urlMap = getPayUrl(payment.getTrade_no());
		payment.setLong_url(String.valueOf(urlMap.get("long_url")));
		payment.setShort_url(String.valueOf(urlMap.get("short_url")));
		payment.setLife_end(System.currentTimeMillis() + WChatPayUtil.time_expire);

		//生成初始订单,等待用户扫码
		WchatOrderVo order = new WchatOrderVo();
		order.setF_wxo_out_trade_no(payment.getTrade_no());
		order.setF_wxo_product_id(payment.getProduct_id());
		order.setF_wxo_trade_status(WchatStatus.waiting_scan.name());
		order.setF_wxo_serverid(payment.getServerid());
		order.setF_wxo_notify_url(payment.getNotify_url());
		order.setF_wxo_total_fee(payment.getProductfee());

		wchatPayDao.insertOrder(order);

		resultMap.put("success", true);
		resultMap.put("payment", payment);
		return resultMap;
	}

	/**
	 * 扫描二维码回调 返回预订单prepay_id
	 */
	public String prePay(String xml){
		Map<String, Object> returnMap = new TreeMap<String, Object>();
		returnMap.put("appid", WChatPayUtil.appid);
		returnMap.put("mch_id", WChatPayUtil.mch_id);
		returnMap.put("result_code", "SUCCESS");
		returnMap.put("nonce_str", WChatPayUtil.randomString(32));
		returnMap.put("return_code", "FAIL");
		returnMap.put("return_msg", "生成预订单失败");
		Map<String, Object> requestMap = XMLUtil.parseXML(xml);
		if(WChatPayUtil.checkSign(requestMap, String.valueOf(requestMap.remove("sign")), WChatPayUtil.tt)){
			//签名校验合法 下单
			Map<String, Object> orderMap = this.unifiedOrder(String.valueOf(requestMap.get("product_id")), String.valueOf(requestMap.get("openid")), String.valueOf(requestMap.get("is_subscribe")));
			returnMap.putAll(orderMap);
		}else{
			//签名不合法
			returnMap.put("return_code", "FAIL");
			returnMap.put("return_msg", "签名失败");
		}
		returnMap.put("sign", WChatPayUtil.sign(returnMap, WChatPayUtil.tt));
		return XMLUtil.createXMLStr(returnMap);
	}
	
	/**
	 * 统一下单API<br/>
	 * <b>这里的product_id是商户订单号</b>
	 */
	public Map<String, Object> unifiedOrder(String product_id, String openid, String is_subscribe){
		Map<String, Object> returnMap = new TreeMap<String, Object>();
		returnMap.put("return_code", "FAIL");
		//获取当前订单
		WchatOrderVo wchatOrder = wchatPayDao.selectOrder(product_id);
		SysProductVo sysProductVo = wchatPayDao.selectProductById(wchatOrder.getF_wxo_product_id());
		//获取产品
		Map<String, Object> map = new TreeMap<String, Object>();
		map.put("appid", WChatPayUtil.appid);
		map.put("mch_id", WChatPayUtil.mch_id);
		map.put("device_info", "WEB");
		map.put("nonce_str", WChatPayUtil.randomString(32));
		map.put("body", sysProductVo.getF_sp_name());
		map.put("attach", "hzkd");
		map.put("out_trade_no", product_id);
		map.put("fee_type", "CNY");//人民币
		map.put("total_fee", wchatOrder.getF_wxo_total_fee());
		map.put("spbill_create_ip", WChatPayUtil.localIp());
		//map.put("spbill_create_ip", "122.224.212.84");
		map.put("time_start", WChatPayUtil.format(new Date()));
		map.put("time_expire", WChatPayUtil.format(new Date(System.currentTimeMillis() + WChatPayUtil.time_expire)));
		map.put("notify_url", SystemConfigUtils.getSysConfig("wchatpay.notify_url"));//异步回调路径
		map.put("trade_type", "NATIVE");
		map.put("product_id", wchatOrder.getF_wxo_product_id());
		map.put("limit_pay", "no_credit");
		map.put("openid", openid);
		map.put("sign", WChatPayUtil.sign(map, WChatPayUtil.tt));
		try {
			String param = XMLUtil.createXMLStr(map);
			long postBefore = System.currentTimeMillis();
			Map<String, String> resultMap = WChatPayUtil.post("https://api.mch.weixin.qq.com/pay/unifiedorder", param);
			String success = resultMap.get("success");
			String msg = resultMap.get("msg");
			LOG.debug("统一下单API参数: " + param + " 返回结果: " + msg + " 耗时:" + (System.currentTimeMillis() - postBefore) + "ms");
			if("1".equals(success)){//post请求成功
				Map<String, Object> orderMap = XMLUtil.parseXML(msg);
				if("SUCCESS".equalsIgnoreCase(String.valueOf(orderMap.get("return_code")))){
					//通信成功
					if(WChatPayUtil.checkSign(orderMap, String.valueOf(orderMap.remove("sign")), WChatPayUtil.tt)){
						//签名正确
						if("SUCCESS".equalsIgnoreCase(String.valueOf(orderMap.get("result_code")))){
							//成功
							LOG.debug("统一下单API成功");
							returnMap.put("return_code", "SUCCESS");
							returnMap.put("prepay_id", orderMap.get("prepay_id"));
							returnMap.put("return_msg", "return_msg");

							//订单记录数据库
							wchatOrder.setF_wxo_out_trade_no(String.valueOf(map.get("out_trade_no")));
							wchatOrder.setF_wxo_prepay_id(String.valueOf(orderMap.get("prepay_id")));
							wchatOrder.setF_wxo_openid(openid);
							wchatOrder.setF_wxo_code_url(String.valueOf(orderMap.get("code_url")));
							wchatOrder.setF_wxo_trade_status(WchatStatus.waiting_pay.name());
							wchatOrder.setF_wxo_trade_type(String.valueOf(map.get("trade_type")));
							wchatOrder.setF_wxo_time_start(String.valueOf(map.get("time_start")));
							wchatOrder.setF_wxo_time_expire(String.valueOf(map.get("time_expire")));
							wchatOrder.setF_wxo_attach(String.valueOf(map.get("attach")));
							wchatOrder.setF_wxo_spbill_create_ip(String.valueOf(map.get("spbill_create_ip")));
							wchatOrder.setF_wxo_is_subscribe(is_subscribe);
							wchatPayDao.updateOrder(wchatOrder);
						}else{
							//失败
							LOG.debug("统一下单API失败: " + orderMap.get("err_code") + "=" + orderMap.get("err_code_des"));
							returnMap.put("return_code", "FAIL");
							returnMap.put("return_msg", orderMap.get("err_code") + " : " + orderMap.get("err_code_des"));
						}
					}else{
						//签名失败
						LOG.debug("统一下单API签名失败");
						returnMap.put("return_code", "FAIL");
						returnMap.put("return_msg", "统一下单API签名验证失败");
					}
				}else{
					//通信失败
					LOG.debug("统一下单API通信失败: " + orderMap.get("return_msg"));
					returnMap.putAll(orderMap);
				}
			}else{//post请求失败
				LOG.debug("统一下单API请求失败:" + msg);
				returnMap.put("return_code", "FAIL");
				returnMap.put("return_msg", "统一下单API请求失败:" + msg);
			}
		} catch (Exception e) {
			returnMap.put("return_code", "FAIL");
			returnMap.put("return_msg", "统一下单API请求失败:");
			LOG.error("Exception ", e);
		}
		return returnMap;
	}
	
	/**
	 * 支付结果回调
	 */
	public String payResult(String xml){
		Map<String, Object> returnMap = new TreeMap<String, Object>();
		returnMap.put("return_code", "FAIL");
		returnMap.put("return_msg", "其他");
		Map<String, Object> resultMap = XMLUtil.parseXML(xml);
		
		if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("return_code")))){
			//通信成功
			if(WChatPayUtil.checkSign(resultMap, String.valueOf(resultMap.remove("sign")), WChatPayUtil.tt)){
				//签名正确
				WchatOrderVo wchatOrder = wchatPayDao.selectOrder(String.valueOf(resultMap.get("out_trade_no")));
				returnMap.put("return_code", "SUCCESS");
				
				if(wchatOrder != null){
					//记录数据库
					wchatOrder.setF_wxo_bank_type(String.valueOf(resultMap.get("bank_type")));
					wchatOrder.setF_wxo_transaction_id(String.valueOf(resultMap.get("transaction_id")));
					wchatOrder.setF_wxo_total_fee(Integer.valueOf(String.valueOf(resultMap.get("total_fee"))));
					wchatOrder.setF_wxo_cash_fee(Integer.valueOf(String.valueOf(resultMap.get("cash_fee"))));
					wchatOrder.setF_wxo_cash_fee_type(String.valueOf(resultMap.get("cash_fee_type")));
					wchatOrder.setF_wxo_is_subscribe(String.valueOf(resultMap.get("is_subscribe")));
					wchatOrder.setF_wxo_time_end(String.valueOf(resultMap.get("time_end")));
					
					if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("result_code")))){
						wchatOrder.setF_wxo_trade_status(WchatStatus.paid.name());
						SysProductVo productVo = wchatPayDao.selectProductById(wchatOrder.getF_wxo_product_id());
						//只有支付成功才会入库userbill
						UserBillVo userbill = new UserBillVo();
						userbill.setF_ub_serverid(wchatOrder.getF_wxo_serverid());
						userbill.setF_ub_productid(wchatOrder.getF_wxo_product_id());
						userbill.setF_ub_info(productVo.getF_sp_name());
						userbill.setF_ub_type(productVo.getF_sp_type());
						userbill.setF_ub_fee(String.valueOf(wchatOrder.getF_wxo_total_fee()));
						userbill.setF_ub_source("微信支付");
						userbill.setF_ui_resolution(1);
						userbill.setF_ub_order_id(wchatOrder.getF_wxo_transaction_id());
						userbill.setF_ub_remark(wchatOrder.getF_wxo_trade_status());
						userbill.setF_ub_ordertime(WChatPayUtil.format(new Date()));
						userbill.setF_ub_endtime(WChatPayUtil.getOrderEndDate(productVo.getF_sp_type()));
						userbill.setF_ub_unsubtime("");
						wchatPayDao.insertUserBill(userbill);
//
//						Map<String, String> bssMap = bssOrder(
//								wchatOrder.getF_wxo_serverid(),
//								wchatOrder.getF_wxo_out_trade_no(),
//								wchatOrder.getF_wxo_transaction_id(),
//								payment.getProductcode(),
//								true);
//
//						String success = bssMap.get("success");
//						String msg = bssMap.get("msg");
//						wchatOrder.setF_wxo_is_bss_order("true".equals(success) ? 1 : 0);
//						wchatOrder.setF_wxo_bss_order_desc(msg);
						
					}else{
						wchatOrder.setF_wxo_trade_status(WchatStatus.fail.name());
						wchatOrder.setF_wxo_desc(String.valueOf(resultMap.get("err_code")) + ":" + String.valueOf(resultMap.get("err_code_des")));
					}
					wchatPayDao.updateOrder(wchatOrder);
				}else{
					LOG.debug("数据库中无订单" + String.valueOf(resultMap.get("out_trade_no")) + "记录");
				}
			}else{
				//签名失败
				LOG.debug("支付结果签名失败");
				returnMap.put("return_code", "FAIL");
				returnMap.put("return_msg", "支付结果签名失败");
			}
		}else{
			//通信失败
			LOG.debug("支付结果通信失败: " + String.valueOf(resultMap.get("return_msg")));
			returnMap.put("return_code", "FAIL");
			returnMap.put("return_msg", "支付结果通信失败: " + String.valueOf(resultMap.get("return_msg")));
		}
		
		return XMLUtil.createXMLStr(returnMap);
	}
	
	/**
	 * 生成下单路径, 并转短路径 返回 长+短 路径
	 * 
	 * @param productid 产品id或订单号
	 * 
	 */
	public Map<String, Object> getPayUrl(@RequestParam(value = "productid") String productid){
		Map<String, Object> map = new TreeMap<String, Object>();
		map.put("appid", WChatPayUtil.appid);
		map.put("mch_id", WChatPayUtil.mch_id);
		map.put("product_id", productid);
		map.put("time_stamp", System.currentTimeMillis());
		map.put("nonce_str", WChatPayUtil.randomString(32));
		map.put("sign", WChatPayUtil.sign(map, WChatPayUtil.tt));
		String url = String.format("weixin://wxpay/bizpayurl?appid=%s&mch_id=%s&nonce_str=%s&product_id=%s&time_stamp=%s&sign=%s", 
				map.get("appid"), map.get("mch_id"), map.get("nonce_str"), map.get("product_id"), map.get("time_stamp"), map.get("sign"));
		
		map.clear();
		
		map.put("appid", WChatPayUtil.appid);
		map.put("mch_id", WChatPayUtil.mch_id);
		map.put("long_url", url);
		map.put("nonce_str", WChatPayUtil.randomString(32));
		map.put("sign", WChatPayUtil.sign(map, WChatPayUtil.tt));
		try {
			String param = XMLUtil.createXMLStr(map);
			long postBefore = System.currentTimeMillis();
			Map<String, String> returnMap = WChatPayUtil.post("https://api.mch.weixin.qq.com/tools/shorturl", param);
			String success = returnMap.get("success");
			String msg = returnMap.get("msg");
			LOG.debug("短路径API参数: " + param + " 返回结果: " + msg + " 耗时:" + (System.currentTimeMillis() - postBefore) + "ms");
			if("1".equals(success)){
				Map<String, Object> resultMap = XMLUtil.parseXML(msg);
				map.clear();
				map.put("long_url", url);
				if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("return_code"))) 
						&& WChatPayUtil.checkSign(resultMap, String.valueOf(resultMap.remove("sign")), WChatPayUtil.tt)){
					map.put("short_url", String.valueOf(resultMap.get("short_url")));
				}else{
					LOG.debug("获取短路径失败:" + msg);
				}
			}else{
				LOG.debug("获取短路径请求失败:" + msg);
			}
		} catch (Exception e) {
			LOG.error("Exception ", e);
		}
		return map;
	}
	
	/**
	 * 查询订单API
	 * 	out_trade_no和transaction_id至少有一个不为空
	 * 	优先使用 transaction_id
	 */
	public WchatOrderResultVo queryOrder(String out_trade_no, String transaction_id){
		if(out_trade_no == null && transaction_id == null){
			LOG.error("out_trade_no 和 transaction_id 至少有一个不能为空!");
			return null;
		}
		
		Map<String, Object> map = new TreeMap<String, Object>();
		map.put("appid", WChatPayUtil.appid);
		map.put("mch_id", WChatPayUtil.mch_id);
		if(out_trade_no != null){
			map.put("out_trade_no", out_trade_no);
		}else{
			map.put("transaction_id", transaction_id);
		}
		map.put("nonce_str", WChatPayUtil.randomString(32));
		map.put("sign", WChatPayUtil.sign(map, WChatPayUtil.tt));
		
		try {
			String param = XMLUtil.createXMLStr(map);
			long postBefore = System.currentTimeMillis();
			Map<String, String> returnMap = WChatPayUtil.post("https://api.mch.weixin.qq.com/pay/orderquery", param);
			String success = returnMap.get("success");
			String msg = returnMap.get("msg");
			LOG.debug("查询订单API参数: " + param + " 返回结果: " + msg + " 耗时:" + (System.currentTimeMillis() - postBefore) + "ms");
			if("1".equals(success)){
				Map<String, Object> resultMap = XMLUtil.parseXML(msg);
				if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("return_code")))){
					//通信成功
					if(WChatPayUtil.checkSign(resultMap, String.valueOf(resultMap.remove("sign")), WChatPayUtil.tt)){
						//签名正确
						if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("result_code")))){
							//成功
							LOG.debug("查询订单成功");
							WchatOrderResultVo orderResult = WChatPayUtil.mapToObj(resultMap, WchatOrderResultVo.class);
							return orderResult;
						}else{
							//失败
							LOG.debug("查询订单失败: " + String.valueOf(resultMap.get("err_code")) + "=" + String.valueOf(resultMap.get("err_code_des")));
						}
					}else{
						//签名失败
						LOG.debug("查询订单签名失败");
					}
				}else{
					//通信失败
					LOG.debug("查询订单通信失败: " + String.valueOf(resultMap.get("return_msg")));
				}
			}else{
				LOG.debug("查询订单请求失败: " + msg);
			}
		} catch (Exception e) {
			LOG.error("Exception ", e);
		}
		return null;
	}
	
	/**
	 * 关闭订单API 
	 * TODO 暂时用不到
	 */
	public WchatOrderResultVo closeOrder(String out_trade_no){
		Map<String, Object> map = new TreeMap<String, Object>();
		map.put("appid", WChatPayUtil.appid);
		map.put("mch_id", WChatPayUtil.mch_id);
		map.put("out_trade_no", out_trade_no);
		map.put("nonce_str", WChatPayUtil.randomString(32));
		map.put("sign", WChatPayUtil.sign(map, WChatPayUtil.tt));
		try {
			String param = XMLUtil.createXMLStr(map);
			long postBefore = System.currentTimeMillis();
			Map<String, String> returnMap = WChatPayUtil.post("https://api.mch.weixin.qq.com/pay/closeorder", param);
			String success = returnMap.get("success");
			String msg = returnMap.get("msg");
			LOG.debug("查询订单API参数: " + param + " 返回结果: " + msg + " 耗时:" + (System.currentTimeMillis() - postBefore) + "ms");
			if("1".equals(success)){
				Map<String, Object> resultMap = XMLUtil.parseXML(msg);
				if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("return_code")))){
					//通信成功
					if(WChatPayUtil.checkSign(resultMap, String.valueOf(resultMap.remove("sign")), WChatPayUtil.tt)){
						//签名正确
						if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("result_code")))){
							//成功
							LOG.debug("关闭订单成功");
							WchatOrderResultVo orderResult = WChatPayUtil.mapToObj(resultMap, WchatOrderResultVo.class);
							return orderResult;
						}else{
							//失败
							LOG.debug("关闭订单失败: " + String.valueOf(resultMap.get("err_code")) + "=" + String.valueOf(resultMap.get("err_code_des")));
						}
					}else{
						//签名失败
						LOG.debug("关闭订单签名失败");
					}
				}else{
					//通信失败
					LOG.debug("关闭订单通信失败: " + String.valueOf(resultMap.get("return_msg")));
				}
			}else{
				LOG.debug("关闭订单请求失败: " + msg);
			}
			
			
		} catch (Exception e) {
			LOG.error("Exception ", e);
		}
		return null;
	}
	
	/**
	 * 退款API
	 * 	out_trade_no和transaction_id至少有一个不为空
	 * 	优先使用 transaction_id
	 */
	public Map<String, String> refund(String out_trade_no){
		Map<String, String> returnMap = new HashMap<String, String>();
		returnMap.put("success", "false");
		WchatOrderVo order = wchatPayDao.selectOrder(out_trade_no);
		if(order == null){
			returnMap.put("msg", "订单号不存在, 不允许退款");
		}else{
			Map<String, Object> map = new TreeMap<String, Object>();
			map.put("appid", WChatPayUtil.appid);
			map.put("mch_id", WChatPayUtil.mch_id);
			map.put("device_info", "WEB");
			map.put("out_refund_no", WChatPayUtil.createRefundNo());
			map.put("total_fee", order.getF_wxo_total_fee());
			map.put("refund_fee", order.getF_wxo_total_fee()/2);
			map.put("refund_fee_type", "CNY");
			map.put("op_user_id", WChatPayUtil.mch_id);
			map.put("out_trade_no", out_trade_no);
			map.put("nonce_str", WChatPayUtil.randomString(32));
			map.put("sign", WChatPayUtil.sign(map, WChatPayUtil.tt));
			String result = WChatPayUtil.postSSL(
					"https://api.mch.weixin.qq.com/secapi/pay/refund", 
					XMLUtil.createXMLStr(map), 
					WChatPayUtil.cert,
					WChatPayUtil.mch_id);
			
			Map<String, Object> resultMap = XMLUtil.parseXML(result);
			if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("return_code")))){
				//通信成功
				if(WChatPayUtil.checkSign(resultMap, String.valueOf(resultMap.remove("sign")), WChatPayUtil.tt)){
					//签名正确
					if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("result_code")))){
						//更新订单状态
						order.setF_wxo_trade_status(WchatStatus.refund.name());
						wchatPayDao.insertOrder(order);
						
						//数据库入退款单
						WchatRefundVo refund = WChatPayUtil.mapToObj(resultMap, WchatRefundVo.class);
						wchatPayDao.insertRefund(refund);
						returnMap.put("success", "true");
						returnMap.put("msg", "退款成功, 已退款: " + map.get("refund_fee") + "分");
					}else{
						//失败
						returnMap.put("msg", "退款失败: " + String.valueOf(resultMap.get("err_code")) + "=" + String.valueOf(resultMap.get("err_code_des")));
					}
				}else{
					//签名失败
					returnMap.put("msg", "退款签名失败");
				}
			}else{
				//通信失败
				returnMap.put("msg", "退款通信失败: " + String.valueOf(resultMap.get("return_msg")));
			}
		}
		return returnMap;
	}
	
	/**
	 * 退款单查询API
	 * 	out_trade_no, transaction_id, out_refund_no, refund_id至少有一个不为空
	 * 	优先使用 refund_id或transaction_id
	 */
	public WchatOrderResultVo refundQuery(String out_trade_no, String transaction_id, String out_refund_no, String refund_id){
		if(out_trade_no == null && transaction_id == null && out_refund_no == null && refund_id == null){
			throw new IllegalArgumentException("out_trade_no, transaction_id, out_refund_no 和 refund_id 至少有一个不能为空!");
		}
		Map<String, Object> map = new TreeMap<String, Object>();
		map.put("appid", WChatPayUtil.appid);
		map.put("mch_id", WChatPayUtil.mch_id);
		map.put("device_info", "WEB");
		if(out_trade_no != null){
			map.put("out_trade_no", out_trade_no);
		}else if(transaction_id != null){
			map.put("transaction_id", transaction_id);
		}else if(out_refund_no != null){
			map.put("out_refund_no", out_refund_no);
		}else if(refund_id != null){
			map.put("refund_id", refund_id);
		}
		map.put("nonce_str", WChatPayUtil.randomString(32));
		map.put("sign", WChatPayUtil.sign(map, WChatPayUtil.tt));
		
		try {
			String param = XMLUtil.createXMLStr(map);
			long postBefore = System.currentTimeMillis();
			Map<String, String> returnMap = WChatPayUtil.post("https://api.mch.weixin.qq.com/pay/refundquery", param);
			String success = returnMap.get("success");
			String msg = returnMap.get("msg");
			LOG.debug("退款订单查询API参数: " + param + " 返回结果: " + msg + " 耗时:" + (System.currentTimeMillis() - postBefore) + "ms");
			if("1".equals(success)){
				Map<String, Object> resultMap = XMLUtil.parseXML(msg);
				if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("return_code")))){
					//通信成功
					if(WChatPayUtil.checkSign(resultMap, String.valueOf(resultMap.remove("sign")), WChatPayUtil.tt)){
						//签名正确
						if("SUCCESS".equalsIgnoreCase(String.valueOf(resultMap.get("result_code")))){
							//成功
							WchatOrderResultVo orderResult = WChatPayUtil.mapToObj(resultMap, WchatOrderResultVo.class);
							return orderResult;
						}else{
							//失败
							LOG.debug("退款查询失败: " + String.valueOf(resultMap.get("err_code")) + "=" + String.valueOf(resultMap.get("err_code_des")));
						}
					}else{
						//签名失败
						LOG.debug("退款查询签名失败");
					}
				}else{
					//通信失败
					LOG.debug("退款查询通信失败: " + String.valueOf(resultMap.get("return_msg")));
				}
			}else{
				LOG.debug("退款查询请求失败: " + msg);
			}
		} catch (Exception e) {
			LOG.error("Exception ", e);
		}
		return null;
	}


	/**
	 * 查询产品
	 */
	public SysProductVo getProduct(String product_id) {
		return wchatPayDao.selectProductById(Integer.valueOf(product_id));
	}
	
	
	/**
	 * 
	 * version测试数据(version url.getBytes("UTF-8").length):
	 * 3 44
	 * 4 64
	 * 5 86
	 * 6 108
	 * 7 124
	 * 8 154
	 * 9 182
	 * 10 216
	 * 11 254
	 * 12 290
	 * 15 415
	 * 20 669
	 * 
	 */
	public BufferedImage getPayQrcode(String url, String logopath) {
		try {
			boolean filepath_check = StringUtils.isNotEmpty(logopath) && !"null".equals(logopath);
			byte[] contentBytes = url.getBytes("UTF-8");
			int version = 11;//254
			if(contentBytes.length > 0 && contentBytes.length < 500){
				if(contentBytes.length < 50){
					version = 4;//64
				}else if(contentBytes.length < 100){
					version = 7;//124
				}else if(contentBytes.length < 150){
					version = 9;//182
				}else if(contentBytes.length < 220){
					version = 11;//254
				}else if(contentBytes.length < 350){
					version = 15;//415
				}else{// 350 -- 499
					version = 20;//669
				}
			}else{
				throw new IllegalArgumentException("url过长度不合法，长度应在 [ 0, 500 ]：" + contentBytes.length);
			}
			
			if(filepath_check)version++;//如果有logo version加一，减少无法识别的概率
			
			int width = 67 + 12 * (version - 1);//设置二维码的大小公式：67 + 12 * （version - 1）  
			int height = 67 + 12 * (version - 1);  
			
			Qrcode qrcodeHandler = new Qrcode();
			// 设置二维码排错率，可选L(7%)、M(15%)、Q(25%)、H(30%)，排错率越高可存储的信息越少，但对二维码清晰度的要求越小
			qrcodeHandler.setQrcodeErrorCorrect('M');
			//编码模式：Numeric 数字, Alphanumeric 英文字母,Binary 二进制,Kanji 汉字(第一个大写字母表示)  
			qrcodeHandler.setQrcodeEncodeMode('B');
			// 设置设置二维码尺寸，取值范围1-40，值越大尺寸越大，可存储的信息越大  
            qrcodeHandler.setQrcodeVersion(version);
			
			BufferedImage bufImg = new BufferedImage(width, height,
					BufferedImage.TYPE_INT_RGB);

			Graphics2D gs = bufImg.createGraphics();

			gs.setBackground(Color.WHITE);
			gs.clearRect(0, 0, width, height);

			// 设定图像颜色> BLACK
			gs.setColor(Color.BLACK);

			// 设置偏移量 不设置可能导致解析出错
			int pixoff = 2;
			// 输出内容> 二维码
			boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);
			for (int i = 0; i < codeOut.length; i++) {
				for (int j = 0; j < codeOut.length; j++) {
					if (codeOut[j][i]) {
						gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);
					}
				}
			}
			
			if(StringUtils.isNotEmpty(logopath) && !"null".equals(logopath)){
				File logoFile = new File(logopath);
				if(logoFile.exists()){
					Image logo = ImageIO
							.read(logoFile);// 实例化一个Image对象。
					int widthLogo = logo.getWidth(null) > bufImg.getWidth() * 2 / 10 ? (bufImg
							.getWidth() * 2 / 10) : logo.getWidth(null), heightLogo = logo
							.getHeight(null) > bufImg.getHeight() * 2 / 10 ? (bufImg
							.getHeight() * 2 / 10) : logo.getWidth(null);

					/**
					 * logo放在中心
					 */
					int x = (bufImg.getWidth() - widthLogo) / 2;
					int y = (bufImg.getHeight() - heightLogo) / 2;
					gs.drawImage(logo, x, y, widthLogo, heightLogo, null);
				}
			}

			gs.dispose();
			bufImg.flush();
			return bufImg;
		} catch (Exception e) {
			LOG.error("Exception ", e);
		}
		return null;
	}

	public WchatOrderVo getOrder(String trade_no) {
		return wchatPayDao.selectOrder(trade_no);
	}

	public String getBackinfo(String type, String trade_no, String secretcode) {
		WchatOrderVo order = wchatPayDao.selectOrder(trade_no);
		Map<String, Object> returnMap = new TreeMap<String, Object>();
		if("paid".equals(order.getF_wxo_trade_status())){
			returnMap.put("code", "00");
			returnMap.put("msg", "支付成功");
		}else if("fail".equals(order.getF_wxo_trade_status())){
			returnMap.put("code", "05");
			returnMap.put("msg", "支付失败");
		}else{
			returnMap.put("code", "16");
			returnMap.put("msg", "订单未支付");
		}
		returnMap.put("out_trade_no", order.getF_wxo_out_trade_no());
		returnMap.put("transaction_id", order.getF_wxo_transaction_id());
		returnMap.put("trade_status", order.getF_wxo_trade_status());
		returnMap.put("total_fee", order.getF_wxo_total_fee());
		returnMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
		returnMap.put("sign", WChatPayUtil.sign(returnMap, secretcode));
		String backinfo = JSONObject.toJSONString(returnMap);
		return backinfo;
	}

	public String authinfo(String json) {
		Map<String, Object> map = JSONObject.parseObject(json);
		String source = String.valueOf(map.get("source"));
		
		Map<String, Object> resultMap = new HashMap<String, Object>();
		resultMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
		resultMap.put("source", source);
	
		String secretcode = SystemConfigUtils.getSysConfig("secret.secretcode." + source);
		if(StringUtils.isNotEmpty(secretcode)){
			if(WChatPayUtil.checkSign(map, String.valueOf(map.remove("sign")), secretcode)){
				String product_id = String.valueOf(map.get("product_id"));
				String serverid = String.valueOf(map.get("serverid"));
				if(StringUtils.isNotEmpty(product_id) && StringUtils.isNotEmpty(serverid)
						 && !"null".equals(product_id) && !"null".equals(serverid)){
					 UserBillVo userbill = wchatPayDao.selectLatestValidUserBill(serverid, product_id, WChatPayUtil.format(new Date()));
					 if(userbill != null){
						resultMap.put("code", "03");
						resultMap.put("msg", "鉴权成功");
					 }else{
						resultMap.put("code", "04");
						resultMap.put("msg", "鉴权失败");
					 }
				}else{
					resultMap.put("code", "01");
					resultMap.put("msg", "参数缺失");
				}
			}else{
				resultMap.put("code", "06");
				resultMap.put("msg", "sign验证失败。");
			}
			resultMap.put("sign", WChatPayUtil.sign(resultMap, secretcode));
		}else{
			resultMap.put("code", "07");
			resultMap.put("msg", "未知来源" + source);
		}
		String result = JSONObject.toJSONString(resultMap);
		return result;
	}

	public Map<String, String> bssOrder(String serverid, String trade_no, String transaction_id, String productcode, boolean order) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("UserName", "regryyg");
		params.put("Userkey", "qazwsx123");
		params.put("ItvAccount", serverid);
		params.put("ProductCode", productcode);
		params.put("OrderSeq", trade_no + "_jdzf");
		params.put("TrainsCode", transaction_id);
		params.put("Action", order ? "1" : "2");
		String SignStr = String.valueOf(params.get("UserName")) + 
				String.valueOf(params.get("Userkey")) + 
				String.valueOf(params.get("ItvAccount")) + 
				String.valueOf(params.get("ProductCode")) + 
				String.valueOf(params.get("OrderSeq")) + 
				String.valueOf(params.get("TrainsCode")) + 
				String.valueOf(params.get("Action")) + 
				"ITDDRBDGZY";
		String Sign = MD5Util.MD5Encode(SignStr, "UTF-8").toUpperCase();
		params.put("Sign", Sign);
		String xmlParam = XMLUtil.createXMLStr(params);
		//http://b.k189.cn:8081/admin/bss/order/orderOrUnsubscribe.do
		//http://172.24.1.8:8081/admin/bss/order/orderOrUnsubscribe.do
		Map<String, String> resultMap = WChatPayUtil.post(SystemConfigUtils.getSysConfig("bss.url.order"), xmlParam);
		String success = resultMap.get("success");
		String msg = resultMap.get("msg");
		
		Map<String, String> returnMap = new HashMap<String, String>();
		if("1".equals(success)){
			Map<String, Object> xmlMap = XMLUtil.parseXML(msg);
			String ReturnCode = String.valueOf(xmlMap.get("ReturnCode"));
			if("0".equals(ReturnCode) || "10008".equals(ReturnCode)){//订购成功或已订购
				returnMap.put("success", "true");
			}else{
				returnMap.put("success", "false");
			}
			returnMap.put("msg", String.valueOf(xmlMap.get("ReturnDesc")));
		}else{
			returnMap.put("success", "false");
			returnMap.put("msg", msg);
		}
		
		return returnMap;
	}
	
	/**
	 * username：regryyg
	 * userkey：qazwsx123
	 */
	public Map<String, String> bssOrderQuery(String serverid, String productcode) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("UserName", SystemConfigUtils.getSysConfig("bss.username"));
		params.put("Userkey", SystemConfigUtils.getSysConfig("bss.userkey"));
		params.put("ItvAccount", serverid);
		params.put("ProductCode", productcode);
		String SignStr = String.valueOf(params.get("UserName")) + 
				String.valueOf(params.get("Userkey")) + 
				String.valueOf(params.get("ItvAccount")) + 
				String.valueOf(params.get("ProductCode")) + 
				"ITDDRBDGZY";
		String Sign = MD5Util.MD5Encode(SignStr, "UTF-8").toUpperCase();
		params.put("Sign", Sign);
		String xmlParam = XMLUtil.createXMLStr(params);
		//http://b.k189.cn:8081/admin/bss/order/orderQuery.do
		//http://172.24.1.8:8081/admin/bss/order/orderQuery.do
		Map<String, String> resultMap = WChatPayUtil.post(SystemConfigUtils.getSysConfig("bss.url.orderquery"), xmlParam);
		String success = resultMap.get("success");
		String msg = resultMap.get("msg");
		
		Map<String, String> returnMap = new HashMap<String, String>();
		if("1".equals(success)){
			Map<String, Object> xmlMap = XMLUtil.parseXML(msg);
			String ReturnCode = String.valueOf(xmlMap.get("ReturnCode"));
			if("10005".equals(ReturnCode)){//已订购
				returnMap.put("success", "true");
			}else{
				returnMap.put("success", "false");
			}
			returnMap.put("msg", String.valueOf(xmlMap.get("ReturnDesc")));
		}else{
			returnMap.put("success", "false");
			returnMap.put("msg", msg);
		}
		
		return returnMap;
	}

}
